package report.msg;

import entity.VehicleRealtimeInfo;
import entity.enums.HikDeviceStatus;
import entity.enums.HikMsgType;
import global.InitCache;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import util.ByteUtil;
import util.WidgetUtil;

import java.nio.ByteBuffer;

/**
 * 报文构造器
 *
 * @author zhouwz
 * @date 2020/11/3 16:43
 */
public class MsgConstructor {

    /**
     * 下发报文构造
     * 固定头部 + 车辆编号 + 指定长度占位数组
     *
     * @param hikMsgType      指令类型
     * @param placeholderSize 空余占位长度(指令类型 - 32 - 4 = 空余占位长度)
     */
    public static ByteBuf issueHeadAndPlaceholder(HikMsgType hikMsgType, Integer placeholderSize) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(hikMsgType.getLen());
        byteBuffer
                .put(new HeadMsg().headToByte(hikMsgType))
                .putInt(InitCache.vehicleCodeInt)
                .put(ByteBuffer.allocateDirect(placeholderSize))
                .flip();
        return convertAndIssue(byteBuffer);
    }

    /**
     * 下发报文构造
     * 固定头部 + 车辆编号 + [自定义字节数组] + 指定长度占位数组
     *
     * @param hikMsgType      指令类型
     * @param bytes           中间插入的内容
     * @param placeholderSize 空余占位长度(指令类型 - 32 - 4 - [自定义字节数组] = 空余占位长度)
     */
    public static ByteBuf issueHeadAndPlaceholder(HikMsgType hikMsgType, byte[] bytes, Integer placeholderSize) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(hikMsgType.getLen());
        byteBuffer
                .put(new HeadMsg().headToByte(hikMsgType))
                .putInt(InitCache.vehicleCodeInt)
                .put(bytes)
                .put(ByteBuffer.allocateDirect(placeholderSize))
                .flip();
        return convertAndIssue(byteBuffer);
    }

    /**
     * 下发报文构造
     * 用于状态主体的构造(区分一般执行机构、探测时候执行机构、带货架执行机构)
     *
     * @param reportDeviceStateReq 上报状态指令
     * @return 对应字节码
     */
    public static ByteBuf issueHeadAndStatusBody(HikMsgType reportDeviceStateReq) {
        VehicleRealtimeInfo realtimeStatus = InitCache.realtimeStatus;
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(reportDeviceStateReq.getLen());
        byteBuffer
                .put(new HeadMsg().headToByte(reportDeviceStateReq))
                .putInt(InitCache.vehicleCodeInt)
                // RCS下发的任务ID和子任务ID需要回应相同的给RCS
                .putShort(InitCache.realtimeStatus.getTaskId() == null ? 0 : realtimeStatus.getTaskId())
                .put(InitCache.realtimeStatus.getSubTaskId() == null ? (byte) 0 : realtimeStatus.getSubTaskId())
                .put(ByteBuffer.allocateDirect(1));
        if (reportDeviceStateReq == HikMsgType.REPORT_DEVICE_STATE_REQ_3) {
            // 探测时候将状态转化为探测的信息 并且 状态为已完成,用于配合上层上报的条件
            byteBuffer.putInt(HikDeviceStatus.STATUS_2.getCode());
        } else {
            byteBuffer.putInt(realtimeStatus.getHikDeviceStatus().getCode());
        }
        byteBuffer
                .putInt((realtimeStatus.getX()))
                .putInt((realtimeStatus.getY()))
                .putInt(realtimeStatus.getAngle() * 1000)
                .put(ByteBuffer.allocateDirect(20))
                .put("XY".getBytes())
                .put(ByteBuffer.allocateDirect(2))
                .putShort((short) 0)
                .putShort((short) 0)
                .put(ByteBuffer.allocateDirect(6))
                .put(realtimeStatus.getPower().byteValue())
                .put(ByteBuffer.allocateDirect(48));
        // 不同执行机构编码
        diffActuatorEncoder(reportDeviceStateReq, byteBuffer);
        byteBuffer.flip();
        return convertAndIssue(byteBuffer);
    }

    /**
     * 不同执行机构编码
     *
     * @param reportDeviceStateReq 区分不同的执行机构状态
     * @param byteBuffer           编码结果
     */
    private static void diffActuatorEncoder(HikMsgType reportDeviceStateReq, ByteBuffer byteBuffer) {
        switch (reportDeviceStateReq) {
            case REPORT_DEVICE_STATE_REQ_3:
                byteBuffer
                        .put((byte) 3)
                        .put(WidgetUtil.getShelfNo32ByteArr())
                        .putInt(0)
                        .putInt(0)
                        .putInt(0)
                        .putInt(0);
                break;
            case REPORT_DEVICE_STATE_REQ_4:
                byteBuffer
                        .put((byte) 4)
                        .put(WidgetUtil.getShelfNo32ByteArr())
                        .putInt(0)
                        .putInt(0)
                        .putInt(0)
                        .put(InitCache.realtimeStatus.getHikLiftStatus().getCode())
                        .put(new byte[3]);
                break;
            default:
                byteBuffer.put((byte) 0);
        }
    }

    /**
     * 点位上报构造
     *
     * @return 构造的实时状态和坐标信息
     */
    public static byte[] nodeConstructor() {
        VehicleRealtimeInfo realtimeStatus = InitCache.realtimeStatus;
        byte[] bytes = new byte[36];
        byte[] angleBytes = ByteUtil.intToByteArray(realtimeStatus.getAngle());
        String x = String.format("%06d", (int) (realtimeStatus.getPoint().getXCoordinate() * 1000));
        String y = String.format("%06d", (int) (realtimeStatus.getPoint().getYCoordinate() * 1000));
        String coordinate = x + "XY" + y;
        System.arraycopy(angleBytes, 0, bytes, 0, angleBytes.length);
        System.arraycopy(coordinate.getBytes(), 0, bytes, angleBytes.length, coordinate.getBytes().length);
        return bytes;
    }

    /**
     * 报文转换并下发
     *
     * @param byteBuffer 字节缓存
     */
    public static ByteBuf convertAndIssue(ByteBuffer byteBuffer) {
        byte[] bytes = new byte[byteBuffer.limit() - byteBuffer.position()];
        byteBuffer.get(bytes);
        return Unpooled.copiedBuffer(bytes);
    }
}
